<?php
$outputBuffering = FALSE;
if ($outputBuffering) {
	ob_start();
}

# Import the application settings.
require_once(dirname(__FILE__) . '/config.php');

# Import the products.
include(APPLICATION_ROOT . '/items.php');

# Import the function code.
require_once(APPLICATION_ROOT . '/includes/functions.php');

# Provide a test transaction.
if (!$_POST) {
	$_POST = array (
		'recipientEmail' => BSDDS_ADMIN_EMAIL,
		'transactionId' => '577EF1154F3240AD5B9B413AA7346A1E',
		'buyerName' => 'Test Buyer',
		'recipientName' => 'Test Recipient',
		'transactionDate' => '1235153369',
		'paymentMethod' => 'CC',
		'status' => 'PS',
		'buyerEmail' => BSDDS_ADMIN_EMAIL,
		'paymentReason' => 'This is where the description goes',
		'referenceId' => '577EF1154F3240AD5B9B413AA7346A1E',
		'transactionAmount' => BSDDS_CURRENCY . ' 10.000000',
		'operation' => 'pay');
}

# Sanitize the inputs which influence the payment method used.
$mc_gross = filter_input(INPUT_POST, 'mc_gross', FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);
$transactionAmount = filter_input(INPUT_POST, 'transactionAmount', FILTER_SANITIZE_STRING);

# If we're logging, log the POST variables used in this transaction.
if (BSDDS_LOGGING) {
	$a = var_export($_POST, TRUE);
	$fp = fopen(BSDDS_LOGFILE, "a");
	fputs($fp, "--- " . date("y/m/d H:i:s", time()) . " ---\n");
	fputs($fp, "Received POST:\n");
	fputs($fp, $a);
	fputs($fp, "\n");
	fclose($fp);
}

# IPN received from Amazon.
if ($transactionAmount) {

	# Process the POST variables.

	# If we're logging, log that this is an Amazon transaction.
	if (BSDDS_LOGGING) {
		$fp = fopen(BSDDS_LOGFILE, "a");
		fputs($fp, "--- POST is Amazon transaction. ---\n");
		fclose($fp);
	}

	# Sanitize the relevant inputs.
	$buyerEmail = filter_input(INPUT_POST, 'buyerEmail', FILTER_SANITIZE_EMAIL);
	$buyerName = filter_input(INPUT_POST, 'buyerName', FILTER_SANITIZE_STRING);
	$referenceId = filter_input(INPUT_POST, 'referenceId', FILTER_SANITIZE_STRING);

	# Check if payment transaction was successful.
	if ($status == "PS") {

		# Update the purchase table.
		$sql = 'UPDATE ' . BSDDS_PURCHASE_TABLE . ' SET email = "'.mysql_escape_string($buyerEmail).'", buyer = "'.mysql_escape_string($buyerName).'", status = "Completed" WHERE txn_id = "'. mysql_escape_string($referenceId) .'"';
		$query = mysql_query($sql);

		# Did the update succeed?
		if (!$query) {
			# If we're logging, log that the transaction failed, and why.
			if (BSDDS_LOGGING) {
				$fp = fopen(BSDDS_LOGFILE, "a");
				fputs($fp, "--- ERROR! - Update after Amazon transaction failed. ---\n");
				fputs($fp, mysql_error() . "\n");
				fclose($fp);
			}
			die(mysql_error());
		}

		$sql = 'SELECT buyer_id FROM ' . BSDDS_PURCHASE_TABLE . ' WHERE txn_id = "'.mysql_escape_string($referenceId).'" LIMIT 1';
		$query = mysql_query($sql) or die(mysql_error());

		# Did we find the buyer ID?
		if (!$query) {
			# If we're logging, log that the transaction failed, and why.
			if (BSDDS_LOGGING) {
				$fp = fopen(BSDDS_LOGFILE, "a");
				fputs($fp, "--- ERROR! - Could not find buyer ID from Amazon transaction. ---\n");
				fputs($fp, mysql_error() . "\n");
				fclose($fp);
			}
			die(mysql_error());
		}

		# Grab the buyer ID.
		$info = mysql_fetch_array($query);

		$mail_To = $buyerEmail;
		$mail_From = BSDDS_CONFIRMATION_FROM_EMAIL;
		$mail_From .= "\r\nX-Mailer: PHP v".phpversion()."\r\n"; // Avoid spam-filters
		$mail_Subject = BSDDS_CONFIRMATION_SUBJECT_LINE;
		$mail_Body = BSDDS_CONFIRMATION_EMAIL_MSG;
		$store_url = WEB_ROOT . "?userid=" . $info['buyer_id'];
		$mail_Body = str_replace("{BUYERS_STORE_URL}", $store_url, $mail_Body);

		$mail = TRUE;

		# If we're logging, log that the transaction was successful.
		if (BSDDS_LOGGING) {
			$fp = fopen(BSDDS_LOGFILE, "a");
			fputs($fp, "--- Amazon transaction payment successful. ---\n");
			fclose($fp);
		}
	}
} else {
	# We're getting a PayPal IPN POST.

	# Read the post from PayPal system and add 'cmd'
	$req = 'cmd=_notify-validate';

	# If we're logging, log that this is an PayPal IPN.
	if (BSDDS_LOGGING) {
		$fp = fopen(BSDDS_LOGFILE, "a");
		fputs($fp, "--- POST is PayPal IPN transaction. ---\n");
		fclose($fp);
	}

	# Sanitize the critical inputs up front.
	$payer_email = filter_input(INPUT_POST, 'payer_email', FILTER_SANITIZE_EMAIL);
	$payer_id = filter_input(INPUT_POST, 'payer_id', FILTER_SANITIZE_STRING);
	$receiver_email = filter_input(INPUT_POST, 'receiver_email', FILTER_SANITIZE_EMAIL);
	$payment_status = filter_input(INPUT_POST, 'payment_status', FILTER_SANITIZE_STRING);
	$mc_currency = filter_input(INPUT_POST, 'mc_currency', FILTER_SANITIZE_STRING);
	$num_cart_items = filter_input(INPUT_POST, 'num_cart_items', FILTER_SANITIZE_NUMBER_INT);
	$txn_id = filter_input(INPUT_POST, 'txn_id', FILTER_SANITIZE_STRING);

	foreach ($_POST as $key => $value) {
		$key = urlencode(stripslashes($key));
		$value = filter_input(INPUT_POST, $key, FILTER_SANITIZE_STRING);
		$value = urlencode(stripslashes($value));
		$req .= "&$key=$value";
	}

	# Post back to PayPal system to validate.
	$header .= "POST /cgi-bin/webscr HTTP/1.0\r\n";
	$header .= "Host: " . PAYPAL_URL . ":80\r\n";
	$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
	$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";

	$fp = fsockopen (PAYPAL_URL, 80, $errno, $errstr, 30);

	$From_email = BSDDS_CONFIRMATION_FROM_EMAIL;
	$From_email .= "\r\nX-Mailer: PHP v".phpversion()."\r\n"; // Avoid spam-filters.
	$Subject_line = BSDDS_CONFIRMATION_SUBJECT_LINE;
	$email_msg = BSDDS_CONFIRMATION_EMAIL_MSG;
	$store_url = filter_var(WEB_ROOT . "?userid=" . $payer_id, FILTER_SANITIZE_URL);
	$email_msg = str_replace("{BUYERS_STORE_URL}", $store_url, $email_msg);

	if (!$fp) {
		# If we're logging, record that we can't contact PayPal.
		if (BSDDS_LOGGING) {
			$fp = fopen(BSDDS_LOGFILE, "a");
			fputs($fp, "--- Warning! Cannot contact PayPal to process IPN!---\n");
			fclose($fp);
		}
		die("Error while attempting to contact PayPal.");
	} else {
		$result = fputs ($fp, $header . $req);
		while (!feof($fp)) {
			$res = fgets ($fp, 1024); # Get something
			if (strcmp ($res, "VERIFIED") == 0) {
				$mail_From = $From_email;
				$mail_To = $payer_email;
				$mail_Subject = $Subject_line;
				$mail_Body = $email_msg;

				# Sanitize the transaction ID for use in the database.
				$db_txn_id = mysql_escape_string($txn_id);

				# Sanitize the critical inputs up front.
				$address_name = filter_input(INPUT_POST, 'address_name', FILTER_SANITIZE_STRING);
				$payer_id = filter_input(INPUT_POST, 'payer_id', FILTER_SANITIZE_STRING);
				$payer_email = filter_input(INPUT_POST, 'payer_email', FILTER_SANITIZE_EMAIL);
				$payment_status = filter_input(INPUT_POST, 'payment_status', FILTER_SANITIZE_STRING);
				$mc_currency = filter_input(INPUT_POST, 'mc_currency', FILTER_SANITIZE_STRING);
				$num_cart_items = filter_input(INPUT_POST, 'num_cart_items', FILTER_SANITIZE_NUMBER_INT);
				$txn_id = filter_input(INPUT_POST, 'txn_id', FILTER_SANITIZE_STRING);

				# Check through all the items in the cart.
				for ($i=1; $i<=$num_cart_items; $i++) {
					$item_name = "item_name" . $i;
					$option_select = "option_selection1_" . $i;
					$mc_gross = "mc_gross_" . $i;
					$quantity = "quantity" . $i;
					$item_id = "item_number" . $i;

					$item['buyer_id'] = mysql_escape_string($payer_id);
					$item['name'] = mysql_escape_string(filter_input(INPUT_POST, $item_name, FILTER_SANITIZE_STRING));
					$item['price'] = mysql_escape_string(filter_input(INPUT_POST, $mc_gross, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
					$item['option'] = mysql_escape_string(filter_input(INPUT_POST, $option_select, FILTER_SANITIZE_STRING));
					$item['buyer'] = mysql_escape_string($payer_email);
					$item['quantity'] = mysql_escape_string(filter_input(INPUT_POST, $quantity, FILTER_SANITIZE_NUMBER_INT));
					$item['txn_id'] = mysql_escape_string($txn_id);
					$item['status'] = mysql_escape_string($payment_status);
					$item['buyername'] = mysql_escape_string($address_name);
					$item['currency'] = mysql_escape_string($mc_currency);
					$item['ID'] = mysql_escape_string(filter_input(INPUT_POST, $item_id, FILTER_SANITIZE_NUMBER_INT));
					$type = mysql_escape_string($products[$item['ID']]['type']);

					# Skip over any item that isn't defined in items.ini, so long as they don't have the same ID.
					# This allows you to combine physical and digital items in the same cart. (Scott Andrew)
					$id = $item['ID'];
					if (!array_key_exists($id, $products)) {
						continue;
					}
					$product = $products[$id];

					# Check that the price is appropriate for the given transaction.
					$price = (float)$item['price'];
					$quantity = (float)$item['quantity'];

					# Extract the product prices and formats.
					$product_prices = array_key_exists('price', $product) ? $product['price'] : Array('0');
					$prices  = split(',', $product_prices);

					# Ensure that the given price is valid for this quantity of product.
					$matched_price = FALSE;
					foreach ($prices as $allowed_price) {
						$allowed_price = (float)trim($allowed_price);
						if (($allowed_price * $quantity) == $price) {
							$matched_price = TRUE;
						}
					}

					# Skip over any unmatched price, as this is likely a fraud attempt.
					if (!$matched_price) {
						# Log the fraud attempt, if logging is enabled.
						if (BSDDS_LOGGING) {
							$fp = fopen(BSDDS_LOGFILE, "a");
							fputs($fp, "!!! Attempted fraud - invalid price $$price for quantity $quantity of product ID $id !!!\n");
							fputs($fp, "!!! Buyer details - $address_name ${payer_email}\n");
							fclose($fp);
						}
						continue;
					}

					# FIXME: This (as well as the original code) seems to have no effect.
					if ($payment_status == "Pending" AND PAYPAL_HOLD_ECHECKS == FALSE) {
						$payment_status == "Completed";
					}

					# Is this the first time we've encountered this transaction?
					$condition = " txn_id = '" . $db_txn_id. "'" .
					             " AND itemID = '" . $item['ID'] . "'" .
					             " AND name = '" . $item['name'] . "'" .
					             " AND price = '" . $item['price'] . "'" .
					             " AND quantity = '" . $item['quantity'] . "'" .
					             " AND buyer = '" . $item['buyername'] . "'" .
					             " AND email = '" . $item['buyer'] . "'" .
					             " AND format = '" . $item['option'] . "'" .
					             " AND currency = '" . $item['currency'] . "'" .
					             " AND buyer_id = '" . $item['buyer_id'] . "'" .
					             " AND type = '" . $type . "'";
					$query = $sql->query("SELECT * FROM " . BSDDS_PURCHASE_TABLE . " WHERE " . $condition);
					$info = mysql_fetch_array($query);
					if (!$info) {
						# This is the first time we've recorded this transaction.
						# Add the purchased items to the database.
						$sql->insert(BSDDS_PURCHASE_TABLE,
							"itemID,name,price,quantity,buyer,email,transaction_time,time,status,txn_id,format,currency,buyer_id,type",
							"'$item[ID]','$item[name]','$item[price]',{$item[quantity]},'$item[buyername]','$item[buyer]',NOW(),NOW(),'$item[status]','$item[txn_id]','$item[option]','$item[currency]','$item[buyer_id]','$type'","");
						$mail = TRUE;

						# If we're logging, record that the transaction insert succeeded.
						if (BSDDS_LOGGING) {
							$fp = fopen(BSDDS_LOGFILE, "a");
							fputs($fp, "--- PayPal transaction succeessful. ---\n");
							fclose($fp);
						}
					} else {
						# We've encountered this transaction before. Just update the status.
						$sql->update(BSDDS_PURCHASE_TABLE, "status = '" . $status . "'", $condition);

						$mail = TRUE;

						# If we're logging, record that the transaction update succeeded.
						if (BSDDS_LOGGING) {
							$fp = fopen(BSDDS_LOGFILE, "a");
							fputs($fp, "--- PayPal transaction update succeessful. ---\n");
							fclose($fp);
						}
					}
				}
			}

			if (strcmp ($res, "INVALID") == 0) {
				/* for error checking
				$mail_From = $From_email;
				$mail_To = BSDDS_ADMIN_EMAIL;
				$mail_Subject = "INVALID IPN POST";
				$mail_Body = "INVALID IPN POST. The raw POST string is below.\n\n" . $req;
				mail($mail_To, $mail_Subject, $mail_Body, $mail_From);
				*/
			}

		}
	}
}

if ($mail) {
	# If we've been directed to send mail, mail the user and the administrator.
	mail($mail_To, $mail_Subject, $mail_Body, $mail_From);
	mail(BSDDS_ADMIN_EMAIL, $mail_Subject, $mail_Body, $mail_From);

	$a = $mail_To . " - " . $mail_Subject . " - " . $mail_Body . " - " . $mail_From;

	# Log the email.
	if (BSDDS_LOGGING) {
		$fp = fopen(BSDDS_LOGFILE, "a");
		fputs($fp, "--- Sending message:\n\n");
		fputs($fp, $a);
		fputs($fp, "\n");
		fclose($fp);
	}
}

# If we're logging, mark the end of this transaction.
if (BSDDS_LOGGING) {
	$fp = fopen(BSDDS_LOGFILE, "a");
	fputs($fp, "--- End notification transaction ---\n");
	fclose($fp);
}

if ($outputBuffering) {
	ob_end_clean();
}
?>